﻿using Microsoft.AspNetCore.Http;
using System.Linq.Expressions;
using YiShop.Framework.Extensions;
using YiShop.Framework.SqlSugar;
using YiShop.Framework.Utils;

namespace YiShop.Framework
{
    public abstract class BaseRepository<TEntity, TDto> : ITransient
        where TEntity : BaseEntity, new()
        where TDto : BaseDto, new()
    {
        public BaseRepository(ISqlSugarRepository<TEntity> sqlSugarRepository)
        {
            Repo = sqlSugarRepository;
        }
        public virtual ISqlSugarRepository<TEntity> Repo { get; set; }

        public abstract ISugarQueryable<TEntity> Queryable(TDto dto);
        public abstract ISugarQueryable<TDto> DtoQueryable(TDto dto);

        protected virtual async Task FillRelatedDataAsync(IEnumerable<TDto> dtos)
        {
            await Task.CompletedTask;
        }


        #region 分页查询
        public async Task<SqlSugarPagedList<TEntity>> GetPagedListAsync(TDto dto)
        {
            var queryable = Queryable(dto);
            return await GetPagedListAsync(queryable);
        }

        public async Task<SqlSugarPagedList<TEntity>> GetPagedListAsync(ISugarQueryable<TEntity> queryable)
        {
            var pageDomain = GetPageDomain();

            SqlSugarPagedList<TEntity> pagedInfo;
            if (!string.IsNullOrEmpty(pageDomain.PropertyName))
            {
                OrderByType? orderByType = (pageDomain.IsAsc ?? "").EqualsIgnoreCase("desc") ? OrderByType.Desc : OrderByType.Asc;
                pagedInfo = await queryable
                    .OrderByPropertyName(pageDomain.PropertyName, orderByType)
                    .ToPagedListAsync(pageDomain.PageNum, pageDomain.PageSize);
            }
            else
            {
                pagedInfo = await queryable.ToPagedListAsync(pageDomain.PageNum, pageDomain.PageSize);
            }

            pagedInfo.Code = StatusCodes.Status200OK;

            return pagedInfo;
        }

        public async Task<SqlSugarPagedList<TDto>> GetDtoPagedListAsync(TDto dto)
        {
            var queryable = DtoQueryable(dto);
            var pagedInfo = await GetDtoPagedListAsync(queryable);

            // 填充关联表数据
            if (pagedInfo.Rows.IsNotEmpty())
            {
                await FillRelatedDataAsync(pagedInfo.Rows);
            }

            return pagedInfo;
        }

        public async Task<SqlSugarPagedList<TDto>> GetDtoPagedListAsync(ISugarQueryable<TDto> queryable)
        {
            var pageDomain = GetPageDomain();

            SqlSugarPagedList<TDto> pagedInfo;
            if (!string.IsNullOrEmpty(pageDomain.PropertyName))
            {
                OrderByType? orderByType = (pageDomain.IsAsc ?? "").EqualsIgnoreCase("desc") ? OrderByType.Desc : OrderByType.Asc;
                pagedInfo = await queryable
                    .OrderByPropertyName(pageDomain.PropertyName, orderByType)
                    .ToPagedListAsync(pageDomain.PageNum, pageDomain.PageSize);
            }
            else
            {
                pagedInfo = await queryable.ToPagedListAsync(pageDomain.PageNum, pageDomain.PageSize);
            }
            pagedInfo.Code = StatusCodes.Status200OK;
            return pagedInfo;
        }

        private static PageDomain GetPageDomain()
        {
            var request = App.HttpContext?.Request;
            var pageNum = !string.IsNullOrEmpty(request?.Query["pageNum"]) ? Convert.ToInt32(request?.Query["pageNum"]) : 1;
            var pageSize = !string.IsNullOrEmpty(request?.Query["pageSize"]) ? Convert.ToInt32(request?.Query["pageSize"]) : 10;
            var orderByColumn = request?.Query["orderByColumn"].ToString();
            var isAsc = request?.Query["isAsc"];

            var orderBy = !string.IsNullOrEmpty(orderByColumn) ? $"{orderByColumn.ToUnderScoreCase()} {isAsc}" : "";

            return new PageDomain
            {
                PageNum = pageNum > 0 ? pageNum : 1,
                PageSize = pageSize > 0 ? pageSize : 10,
                OrderByColumn = orderByColumn,
                PropertyName = orderByColumn?.ToUpperCamelCase(),
                OrderBy = orderBy,
                IsAsc = isAsc
            };
        }
        #endregion

        public async Task<bool> AnyAsync(TDto dto)
        {
            return await Queryable(dto).AnyAsync();
        }

        public async Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await Repo.CountAsync(predicate);
        }

        public int Count(TDto dto)
        {
            return Queryable(dto).Count();
        }

        #region 第一项
        public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await Repo.FirstOrDefaultAsync(predicate);
        }

        public async Task<TDto> GetDtoFirstAsync(TDto dto)
        {
            return await DtoQueryable(dto).FirstAsync();
        }

        public async Task<TEntity> GetFirstAsync(TDto dto)
        {
            return await Queryable(dto).FirstAsync();
        }
        #endregion

        public async Task<List<TDto>> GetDtoListAsync(TDto dto)
        {
            var dtos = await DtoQueryable(dto).ToListAsync();

            // 填充关联表数据
            if (dtos.IsNotEmpty())
            {
                await FillRelatedDataAsync(dtos);
            }

            return dtos;
        }

        public async Task<List<TEntity>> GetListAsync(TDto dto)
        {
            return await Queryable(dto).ToListAsync();
        }

        #region 增删改
        /// <summary>
        /// 添加一条数据，自动生成主键
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public async Task<bool> InsertAsync(TEntity entities)
        {
            SetCreateUserInfo(entities);
            return await Repo.InsertReturnIndentityIntoEntityAsync(entities);
        }

        /// <summary>
        /// 添加多条
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public async Task<int> InsertAsync(IEnumerable<TEntity> entities)
        {
            SetCreateUserInfo(entities);
            return await Repo.InsertAsync(entities);
        }

        /// <summary>
        /// 修改一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="ignoreAllNullColumns"></param>
        /// <returns></returns>
        public async Task<int> UpdateAsync(TEntity entity, bool ignoreAllNullColumns = false)
        {
            SetUpdateUserInfo(entity);
            return await Repo.UpdateAsync(entity, ignoreAllNullColumns);
        }
        /// <summary>
        /// 修改一条数据单个项
        /// </summary>
        /// <returns></returns>
        public IUpdateable<TEntity> Updateable()
        {
            if (typeof(TEntity) == typeof(UserBaseEntity))
            {
                return Repo.Context.Updateable<TEntity>()
                    .SetColumns("update_time", DateTime.Now)
                    .SetColumns("update_by", SecurityUtils.GetUsername());
            }
            else
            {
                return Repo.Context.Updateable<TEntity>();
            }
        }

        public IUpdateable<TEntity> Updateable(TEntity entity)
        {
            this.SetUpdateUserInfo(entity);
            return Repo.Context.Updateable<TEntity>(entity);
        }

        /// <summary>
        /// 删除一条记录
        /// </summary>
        /// <param name="key"></param>
        public async Task<int> DeleteAsync<TKey>(TKey key)
        {
            return await Repo.DeleteAsync(key);
        }

        /// <summary>
        /// 删除多条记录
        /// </summary>
        /// <param name="keys"></param>
        public async Task<int> DeleteAsync<TKey>(TKey[] keys)
        {
            return await Repo.DeleteAsync(keys);
        }

        // 新增时: 设置 用户信息
        private void SetCreateUserInfo(TEntity entity)
        {
            var baseType = typeof(TEntity).BaseType;
            if (baseType != typeof(UserBaseEntity) && baseType != typeof(CreateUserBaseEntity)) return;

            ReflectUtils.SetPropertyValue(entity, "CreateBy", SecurityUtils.GetUsername()!);
            ReflectUtils.SetPropertyValue(entity, "CreateTime", DateTime.Now);
        }
        private void SetCreateUserInfo(IEnumerable<TEntity> entities)
        {
            var baseType = typeof(TEntity).BaseType;
            if (baseType != typeof(UserBaseEntity) && baseType != typeof(CreateUserBaseEntity)) return;
            foreach (TEntity entity in entities)
            {
                this.SetCreateUserInfo(entity);
            }
        }

        // 更新时: 设置 用户信息
        private void SetUpdateUserInfo(TEntity entity)
        {
            if (typeof(TEntity).BaseType != typeof(UserBaseEntity)) return;

            ReflectUtils.SetPropertyValue(entity, "UpdateBy", SecurityUtils.GetUsername()!);
            ReflectUtils.SetPropertyValue(entity, "UpdateTime", DateTime.Now);
        }
        private void SetUpdateUserInfo(IEnumerable<TEntity> entities)
        {
            if (typeof(TEntity).BaseType != typeof(UserBaseEntity)) return;
            foreach (TEntity entity in entities)
            {
                this.SetUpdateUserInfo(entity);
            }
        }
        #endregion

        public ISugarQueryable<TEntity> SqlQueryable(string sql, List<SugarParameter> parameters)
        {
            return Repo.SqlQueryable(sql, parameters);
        }

    }
}
